package com.example.singing.util;

import com.example.singing.manager.SystemConfigManager;
import com.example.singing.model.SystemConfig;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.*;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 数据备份和恢复管理器
 * 提供完整的数据备份、恢复、导入导出功能
 */
public class BackupManager {
    private static BackupManager instance;
    private SystemConfigManager configManager;
    private SystemConfig config;
    private static final String BACKUP_DIR = "backups";
    private static final String TEMP_DIR = "temp";
    
    private BackupManager() {
        this.configManager = new SystemConfigManager();
        this.config = configManager.getConfig();
        createDirectories();
    }
    
    public static BackupManager getInstance() {
        if (instance == null) {
            instance = new BackupManager();
        }
        return instance;
    }
    
    /**
     * 创建必要的目录
     */
    private void createDirectories() {
        try {
            Files.createDirectories(Paths.get(BACKUP_DIR));
            Files.createDirectories(Paths.get(TEMP_DIR));
        } catch (IOException e) {
            System.err.println("创建目录失败: " + e.getMessage());
        }
    }
    
    /**
     * 创建完整系统备份
     */
    public String createFullBackup() {
        try {
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            String backupFileName = "full_backup_" + timestamp + ".zip";
            String backupPath = BACKUP_DIR + File.separator + backupFileName;
            
            try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(Paths.get(backupPath)))) {
                // 备份数据文件
                backupDataFiles(zipOut);
                
                // 备份用户上传文件
                backupUserUploads(zipOut);
                
                // 备份配置文件
                backupConfigFiles(zipOut);
                
                // 创建备份信息文件
                createBackupInfo(zipOut, timestamp);
            }
            
            // 记录备份信息
            config.addBackupRecord(backupPath);
            config.addSystemLog("完整系统备份已创建: " + backupPath);
            configManager.saveConfig();
            
            // 清理旧备份
            cleanupOldBackups();
            
            return backupPath;
        } catch (Exception e) {
            System.err.println("创建备份失败: " + e.getMessage());
            config.addSystemLog("创建备份失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 备份数据文件
     */
    private void backupDataFiles(ZipOutputStream zipOut) throws IOException {
        String[] dataFiles = {"users.dat", "teams.dat", "competitions.dat", "scores.dat", "system_config.dat"};
        
        for (String fileName : dataFiles) {
            File file = new File(fileName);
            if (file.exists()) {
                ZipEntry zipEntry = new ZipEntry("data/" + fileName);
                zipOut.putNextEntry(zipEntry);
                Files.copy(file.toPath(), zipOut);
                zipOut.closeEntry();
            }
        }
    }
    
    /**
     * 备份用户上传文件
     */
    private void backupUserUploads(ZipOutputStream zipOut) throws IOException {
        File uploadDir = new File("user_uploads");
        if (uploadDir.exists() && uploadDir.isDirectory()) {
            File[] uploadFiles = uploadDir.listFiles();
            if (uploadFiles != null) {
                for (File uploadFile : uploadFiles) {
                    if (uploadFile.isFile()) {
                        ZipEntry zipEntry = new ZipEntry("user_uploads/" + uploadFile.getName());
                        zipOut.putNextEntry(zipEntry);
                        Files.copy(uploadFile.toPath(), zipOut);
                        zipOut.closeEntry();
                    }
                }
            }
        }
    }
    
    /**
     * 备份配置文件
     */
    private void backupConfigFiles(ZipOutputStream zipOut) throws IOException {
        // 备份系统配置
        ZipEntry configEntry = new ZipEntry("config/system_config.dat");
        zipOut.putNextEntry(configEntry);
        // 将配置对象序列化到字节数组，然后写入ZIP
        java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
        oos.writeObject(config);
        oos.close();
        zipOut.write(baos.toByteArray());
        zipOut.closeEntry();
        
        // 备份其他可能的配置文件
        String[] configFiles = {"application.properties", "log4j.properties", "database.properties"};
        for (String configFile : configFiles) {
            File file = new File(configFile);
            if (file.exists()) {
                ZipEntry zipEntry = new ZipEntry("config/" + configFile);
                zipOut.putNextEntry(zipEntry);
                Files.copy(file.toPath(), zipOut);
                zipOut.closeEntry();
            }
        }
    }
    
    /**
     * 创建备份信息文件
     */
    private void createBackupInfo(ZipOutputStream zipOut, String timestamp) throws IOException {
        ZipEntry infoEntry = new ZipEntry("backup_info.txt");
        zipOut.putNextEntry(infoEntry);
        
        StringBuilder info = new StringBuilder();
        info.append("备份信息\n");
        info.append("========\n");
        info.append("备份时间: ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("\n");
        info.append("备份类型: 完整系统备份\n");
        info.append("系统版本: ").append(config.getVersion()).append("\n");
        info.append("备份文件: ").append(timestamp).append("\n");
        info.append("\n包含内容:\n");
        info.append("- 用户数据 (users.dat)\n");
        info.append("- 队伍数据 (teams.dat)\n");
        info.append("- 比赛数据 (competitions.dat)\n");
        info.append("- 评分数据 (scores.dat)\n");
        info.append("- 系统配置 (system_config.dat)\n");
        info.append("- 用户上传文件 (user_uploads/)\n");
        info.append("- 配置文件 (config/)\n");
        
        zipOut.write(info.toString().getBytes("UTF-8"));
        zipOut.closeEntry();
    }
    
    /**
     * 从备份恢复系统
     */
    public boolean restoreFromBackup(String backupPath) {
        try {
            // 显示确认对话框
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle("确认恢复");
            alert.setHeaderText("从备份恢复系统");
            alert.setContentText("确定要从备份文件恢复系统吗？这将覆盖当前的所有数据。\n备份文件: " + backupPath);
            
            Optional<ButtonType> result = alert.showAndWait();
            if (!result.isPresent() || result.get() != ButtonType.OK) {
                return false;
            }
            
            // 创建当前数据的临时备份
            String tempBackup = createFullBackup();
            if (tempBackup == null) {
                AlertUtil.showErrorAlert("恢复失败", "无法创建当前数据的备份");
                return false;
            }
            
            // 解压备份文件
            try (ZipInputStream zipIn = new ZipInputStream(Files.newInputStream(Paths.get(backupPath)))) {
                ZipEntry entry;
                while ((entry = zipIn.getNextEntry()) != null) {
                    String entryName = entry.getName();
                    File entryFile = new File(entryName);
                    
                    // 确保父目录存在
                    if (entryFile.getParent() != null) {
                        Files.createDirectories(Paths.get(entryFile.getParent()));
                    }
                    
                    // 跳过目录
                    if (entry.isDirectory()) {
                        continue;
                    }
                    
                    // 解压文件
                    try (FileOutputStream fos = new FileOutputStream(entryFile)) {
                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = zipIn.read(buffer)) > 0) {
                            fos.write(buffer, 0, length);
                        }
                    }
                    
                    zipIn.closeEntry();
                }
            }
            
            config.addSystemLog("系统已从备份恢复: " + backupPath);
            configManager.saveConfig();
            
            AlertUtil.showInfoAlert("恢复成功", "系统已从备份成功恢复");
            return true;
            
        } catch (Exception e) {
            System.err.println("恢复备份失败: " + e.getMessage());
            config.addSystemLog("恢复备份失败: " + e.getMessage());
            AlertUtil.showErrorAlert("恢复失败", "恢复备份时发生错误: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 导出数据到指定格式
     */
    public boolean exportData(String format, String filePath) {
        try {
            switch (format.toLowerCase()) {
                case "json":
                    return exportToJSON(filePath);
                case "csv":
                    return exportToCSV(filePath);
                case "xml":
                    return exportToXML(filePath);
                default:
                    AlertUtil.showErrorAlert("导出失败", "不支持的导出格式: " + format);
                    return false;
            }
        } catch (Exception e) {
            System.err.println("导出数据失败: " + e.getMessage());
            AlertUtil.showErrorAlert("导出失败", "导出数据时发生错误: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 导出为JSON格式
     */
    private boolean exportToJSON(String filePath) throws IOException {
        // 这里可以实现JSON导出逻辑
        // 由于需要JSON库，这里只是占位符
        config.addSystemLog("数据已导出为JSON格式: " + filePath);
        return true;
    }
    
    /**
     * 导出为CSV格式
     */
    private boolean exportToCSV(String filePath) throws IOException {
        try (PrintWriter writer = new PrintWriter(new FileWriter(filePath))) {
            // 写入CSV头部
            writer.println("数据类型,ID,名称,创建时间,最后修改时间");
            
            // 这里可以添加具体的数据导出逻辑
            // 由于需要访问各个Manager，这里只是示例
            
            config.addSystemLog("数据已导出为CSV格式: " + filePath);
            return true;
        }
    }
    
    /**
     * 导出为XML格式
     */
    private boolean exportToXML(String filePath) throws IOException {
        // 这里可以实现XML导出逻辑
        // 由于需要XML库，这里只是占位符
        config.addSystemLog("数据已导出为XML格式: " + filePath);
        return true;
    }
    
    /**
     * 从文件导入数据
     */
    public boolean importData(String format, String filePath) {
        try {
            switch (format.toLowerCase()) {
                case "json":
                    return importFromJSON(filePath);
                case "csv":
                    return importFromCSV(filePath);
                case "xml":
                    return importFromXML(filePath);
                default:
                    AlertUtil.showErrorAlert("导入失败", "不支持的导入格式: " + format);
                    return false;
            }
        } catch (Exception e) {
            System.err.println("导入数据失败: " + e.getMessage());
            AlertUtil.showErrorAlert("导入失败", "导入数据时发生错误: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 从JSON导入
     */
    private boolean importFromJSON(String filePath) throws IOException {
        // 这里可以实现JSON导入逻辑
        config.addSystemLog("数据已从JSON格式导入: " + filePath);
        return true;
    }
    
    /**
     * 从CSV导入
     */
    private boolean importFromCSV(String filePath) throws IOException {
        // 这里可以实现CSV导入逻辑
        config.addSystemLog("数据已从CSV格式导入: " + filePath);
        return true;
    }
    
    /**
     * 从XML导入
     */
    private boolean importFromXML(String filePath) throws IOException {
        // 这里可以实现XML导入逻辑
        config.addSystemLog("数据已从XML格式导入: " + filePath);
        return true;
    }
    
    /**
     * 清理旧备份文件
     */
    private void cleanupOldBackups() {
        try {
            File backupDir = new File(BACKUP_DIR);
            if (!backupDir.exists()) return;
            
            File[] backupFiles = backupDir.listFiles((dir, name) -> 
                name.startsWith("full_backup_") && name.endsWith(".zip"));
            
            if (backupFiles == null) return;
            
            // 按修改时间排序
            List<File> sortedFiles = new ArrayList<>();
            for (File file : backupFiles) {
                sortedFiles.add(file);
            }
            sortedFiles.sort((f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified()));
            
            // 删除超出限制的备份文件
            int maxBackups = config.getMaxBackupFiles();
            while (sortedFiles.size() > maxBackups) {
                File oldBackup = sortedFiles.remove(0);
                if (oldBackup.delete()) {
                    config.addSystemLog("已删除旧备份: " + oldBackup.getName());
                }
            }
        } catch (Exception e) {
            System.err.println("清理旧备份失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取备份文件列表
     */
    public List<String> getBackupList() {
        List<String> backupList = new ArrayList<>();
        try {
            File backupDir = new File(BACKUP_DIR);
            if (backupDir.exists()) {
                File[] backupFiles = backupDir.listFiles((dir, name) -> 
                    name.endsWith(".zip"));
                if (backupFiles != null) {
                    for (File file : backupFiles) {
                        backupList.add(file.getAbsolutePath());
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("获取备份列表失败: " + e.getMessage());
        }
        return backupList;
    }
    
    /**
     * 验证备份文件完整性
     */
    public boolean validateBackup(String backupPath) {
        try {
            try (ZipInputStream zipIn = new ZipInputStream(Files.newInputStream(Paths.get(backupPath)))) {
                ZipEntry entry;
                int fileCount = 0;
                while ((entry = zipIn.getNextEntry()) != null) {
                    fileCount++;
                    // 检查关键文件是否存在
                    if (entry.getName().equals("backup_info.txt")) {
                        // 验证备份信息文件
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = zipIn.read(buffer)) > 0) {
                            baos.write(buffer, 0, length);
                        }
                        String info = baos.toString("UTF-8");
                        if (!info.contains("备份信息")) {
                            return false;
                        }
                    }
                    zipIn.closeEntry();
                }
                return fileCount > 0;
            }
        } catch (Exception e) {
            System.err.println("验证备份文件失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 显示备份选择对话框
     */
    public String showBackupSelectionDialog(Stage stage) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择备份文件");
        fileChooser.getExtensionFilters().addAll(
            new FileChooser.ExtensionFilter("ZIP文件", "*.zip"),
            new FileChooser.ExtensionFilter("所有文件", "*.*")
        );
        
        File selectedFile = fileChooser.showOpenDialog(stage);
        return selectedFile != null ? selectedFile.getAbsolutePath() : null;
    }
    
    /**
     * 显示导出选择对话框
     */
    public String showExportSelectionDialog(Stage stage, String format) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("导出数据");
        fileChooser.getExtensionFilters().addAll(
            new FileChooser.ExtensionFilter(format.toUpperCase() + "文件", "*." + format.toLowerCase()),
            new FileChooser.ExtensionFilter("所有文件", "*.*")
        );
        
        File selectedFile = fileChooser.showSaveDialog(stage);
        return selectedFile != null ? selectedFile.getAbsolutePath() : null;
    }
}
